package cc.mrbird.febs.common.oss;

import cc.mrbird.febs.common.exception.FebsException;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

public class OssConfig {

    static String[] TYPESTR = {".png",".jpg",".gif",".jpeg",".doc",".docx",".xlsx"};

    public OSS ossClient = this.getOssClient();

    public static OSS getOssClient() {
        if (OSSConstant.ACCESS_KEY_ID ==null){
            OSSConstant.END_POINT = "http://oss-cn-beijing.aliyuncs.com";
            OSSConstant.ACCESS_KEY_ID = "LTAI4Fkr7MrNxGnGwTCRSN5S";
            OSSConstant.ACCESS_KEY_SECRET = "NbiJg6RA9xx8bqyh4d14VP8loUj2VE";
            OSSConstant.BUCKET_NAME = "macwoss";
        }
        OSS ossClient = new OSSClientBuilder().build(OSSConstant.END_POINT, OSSConstant.ACCESS_KEY_ID, OSSConstant.ACCESS_KEY_SECRET);
        ossClient.setBucketAcl(OSSConstant.BUCKET_NAME, CannedAccessControlList.PublicRead);
        return ossClient;
    }

    public static String upload(MultipartFile file,String basePath) {

        Boolean flag = false;
        for (String type : TYPESTR) {
            if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) {
                flag = true;
                break;
            }
        }
        if (!flag) {
            throw new FebsException("文件格式不正确");
        }

        String uploadUrl = "";
        try {
//            //2、怎么判断文件内容—> 如果我上传的是rm -rf /* 脚本
//            BufferedImage image = ImageIO.read(file.getInputStream());
//            if (image == null) {
//                throw new FebsException("文件内容不正确");
//                return "文件内容不正确";
//            } else {
//                System.err.println(image.getHeight());
//                System.err.println(image.getWidth());
//            }
            //判断oss实例是否存在：如果不存在则创建，如果存在则获取
            OSS ossClient = getOssClient();
            if (!ossClient.doesBucketExist(OSSConstant.BUCKET_NAME)) {
                //创建bucket
                ossClient.createBucket(OSSConstant.BUCKET_NAME);
                //设置oss实例的访问权限：公共读
                ossClient.setBucketAcl(OSSConstant.BUCKET_NAME, CannedAccessControlList.PublicRead);
            }

            //获取上传文件流
            InputStream inputStream = file.getInputStream();

            //构建日期路径：avatar/2019/02/26/文件名
            String filePath = new DateTime().toString("yyyy/MM/dd");

            //文件名：uuid/原始文件名到后缀
            String original = file.getOriginalFilename();
            String fileName = UUID.randomUUID().toString().replace("-","");
//            String fileType = original.substring(original.lastIndexOf("."));
            String newName = fileName +"/"+ original;
            String fileUrl = basePath+"/" + filePath + "/" + newName;
            System.out.println(fileUrl);
            //文件上传至阿里云
            ossClient.putObject(OSSConstant.BUCKET_NAME, fileUrl, inputStream);

            // 关闭OSSClient。
            ossClient.shutdown();

            //获取url地址
            uploadUrl =  OSSConstant.FILE_HOST+"/"+fileUrl;

        } catch (IOException e) {
           throw new FebsException("文件上传异常！");
        }
        return uploadUrl;
    }



    /**
     * 实现阿里云OSS的文件预览功能
     * @param objectName
     */
   /* public static  void previewOss(String objectName){
        OSS ossClient = getOssClient();
        //文档预览 获取 signURL
        String  process = "imm/previewdoc,copy_1";
        ossClient.
        JSONObject params = {};
        params.update({bucket.PROCESS: process})
        url = bucket.sign_url("GET", objectKey, 3600, params=params)

    }*/

    /**
     * @param ossClient  oss客户端
     * @param bucketName bucket名称
     * @return List<String>  文件路径和大小集合
     * @throws
     * @Title: queryAllObject
     * @Description: 查询某个bucket里面的所有文件
     */
    public static List<String> queryAllObject(OSS ossClient, String bucketName) {
        List<String> results = new ArrayList<String>();
        try {
            // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
            ObjectListing objectListing = ossClient.listObjects(bucketName);
            // objectListing.getObjectSummaries获取所有文件的描述信息。
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                results.add(" - " + objectSummary.getKey() + "  " + "(size = " + objectSummary.getSize() + ")");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return results;
    }


    /**
     * 从OSS服务中下载所需文件到本地临时文件
     * @param objectName 要下载的对象/文件
     * @return
     */
    public static String downloadOSS(String objectName) {
        String basePath = "src/main/resources/files";
        OSS ossClient = null;
        try {
            //创建OSSClient实例，用于操作oss空间
            ossClient = getOssClient();
            //指定文件保存路径
            String filePath = basePath + "/" + objectName.substring(0, objectName.lastIndexOf("/"));
            System.out.println(filePath);
            //判断文件目录是否存在，不存在则创建
            File file = new File(filePath);
            if (!file.exists()) {
                file.mkdirs();
            }
            //判断保存文件名是否加后缀
            if (objectName.contains(".")) {
                //指定文件保存名称
                filePath = filePath + "/" + objectName.substring(objectName.lastIndexOf("/") + 1);
            }

            //获取OSS文件并保存到本地指定路径中，此文件路径一定要存在，若保存目录不存在则报错，若保存文件名已存在则覆盖本地文件
            ossClient.getObject(new GetObjectRequest(OSSConstant.BUCKET_NAME, objectName), new File(filePath));
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            //关闭oss连接
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return basePath;
    }

    /**
     * 从OSS服务中下载所需文件到本地临时文件
     * @param objectNames 要下载的对象/文件
     * @return
     */
    private static String downloadOSS(List<String> objectNames) {
        String basePath = "src/main/resources/files";
        OSS ossClient = null;
        try {
            //创建OSSClient实例，用于操作oss空间
            ossClient = getOssClient();
            for (String objectName : objectNames) {
                //指定文件保存路径
                String filePath = basePath + "/" + objectName.substring(32, objectName.lastIndexOf("/"));
                //判断文件目录是否存在，不存在则创建
                File file = new File(filePath);
                if (!file.exists()) {
                    file.mkdirs();
                }
                //判断保存文件名是否加后缀
                if (objectName.contains(".")) {
                    //指定文件保存名称
                    filePath = filePath + "/" + objectName.substring(objectName.lastIndexOf("/") + 1);
                }
                //获取OSS文件并保存到本地指定路径中，此文件路径一定要存在，若保存目录不存在则报错，若保存文件名已存在则覆盖本地文件
                ossClient.getObject(new GetObjectRequest(OSSConstant.BUCKET_NAME, objectName), new File(filePath));
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            //关闭oss连接
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return basePath;
    }

    /**
     * 从OSS服务中下载所需文件到本地临时文件，并将文件以ZIP格式进行压缩
     *
     * @param objectNames 要下载的对象/文件
     * @param zipName     zip文件名
     * @throws Exception
     */
    public static void fileToZip(List<String> objectNames, String zipName) throws Exception {
        File file = null;
        try {
            //调用方法获取OSS中的文件
            String fileName = downloadOSS(objectNames);
            //获取待压缩文件源
            file = new File(fileName);
            //指定压缩文件存放路径
            String zipFileName = "src/main/resources/zipFiles/" + zipName + ".zip";
            File zipFile = new File(zipFileName);
            //构建输出流
            FileOutputStream fout = new FileOutputStream(zipFile);
            //构建压缩输出流
            ArchiveOutputStream aos = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, fout);
            //判断获取的压缩实例是否为zip格式
            if (aos instanceof ZipArchiveOutputStream) {
                //进行压缩实例强转
                ZipArchiveOutputStream zipos = (ZipArchiveOutputStream) aos;
                //将指定文件封装成压缩项，添加到压缩流中
                //判断文件是否存在
                if (file.exists()) {
                    //判断文件类型，调用文件处理方法
                    zipDir(zipos, file, "");
                }
            }
            //关闭流
            aos.flush();
            aos.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } finally {
            //删除文件源，只保留zip文件
            if (file.exists()) {
                //判断文件类型
                if (file.isDirectory()) {
                    //对文件夹进行处理递归删除（有内容的文件夹不能直接被删除）
                    deleteFile(file);
                    file.delete();//删除空文件夹
                } else {
                    file.delete();//文件直接删除
                }
            }
        }
    }

    /**
     * 对压缩文件夹进行循环处理
     *
     * @param zipos   压缩流
     * @param file    要处理的文件
     * @param baseDir 要处理的文件的文件夹路径
     * @throws IOException
     */
    private static void zipDir(ZipArchiveOutputStream zipos, File file, String baseDir) throws IOException {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                //对文件进行递归判断
                zipDir(zipos, f, baseDir + file.getName() + File.separator);
            }
        } else {
            //将文件封装成压缩项
            //根据文件创建zip内容实体
            ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(file, baseDir + file.getName());
            //将根据文件创建的实体保存到压缩流中
            zipos.putArchiveEntry(zipArchiveEntry);
            //将内容输出到压缩文件中
            zipos.write(FileUtils.readFileToByteArray(file));
            zipos.closeArchiveEntry();
        }
    }

    /**
     * 文件及文件夹的递归删除
     *
     * @param file
     */
    private static void deleteFile(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                deleteFile(f);
                //将循环后的空文件夹删除
                if (f.exists()) {
                    f.delete();
                }
            }
        } else {
            file.delete();
        }
    }

    public static void main(String[] args) {
        ArrayList<String> fileNames = new ArrayList<>();
        //oss的存储空间内部是扁平的，没有文件系统目录概念，所有的对象都隶属于其对应的存储空间，在下载是必须明确的指出要下在的文件，指定其上层（文件系统概念）文件夹，无法下载其内部文件
        //fileNames.add("image1/"); //WARN com.aliyun.oss - Cannot read object content stream: src\main\resources\files\image1 (拒绝访问。)
        fileNames.add("image1/image2/2.jpg");
        fileNames.add("image1/image2/3.jpg");
        fileNames.add("image1/0.jpg");
        try {
            //此连接OSS资源为本人OSS服务资源，可供学习人员进行下载测试，请勿做它用
            fileToZip(fileNames, "testImage");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
